#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time      :2022/6/2 14:23
# @Author    :cjw
import time
from typing import List, Optional

import allure
import pytest

from app_wework.base.base_app import BaseApp
from app_wework.page.main_page import MainPage
from app_wework.util.generate_data import GenerateData
from app_wework.util.log import logger
from app_wework.util.appium_device_sync import AppiumDeviceSync

app: Optional[BaseApp] = None  # 初始化app对象
m_page: Optional[MainPage] = None  # 企业微信app主页
gd: GenerateData = GenerateData()  # 虚拟数据生成
is_run: bool = False  # appium 服务启动结果


@pytest.fixture(scope='session', autouse=True)
def start_appium_server():
	"""appium服务启动"""
	global is_run
	# 并发启动appium服务
	is_run = AppiumDeviceSync.appium_server_start_sync()


@pytest.fixture(scope='class')
def app_init():
	"""每个测试用例类，创建一个driver"""
	global app
	# 初始化app
	# 如果放在setup里，会每次都创建一个新的app实例，产生一个新的session
	while not is_run:
		# 等待appium服务启动成功
		time.sleep(2)
	app = BaseApp()
	yield
	app.quit()


@pytest.fixture()
def app_main_page():
	"""每个用例执行，初始化主页面"""
	global m_page

	while not app:
		# 等待app初始化
		time.sleep(2)
	m_page = app.start().goto_main()
	yield m_page, gd
	app.close_app()


@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
	"""
	获取每个用例状态的钩子函数，进行失败用例截图

	具体执行过程如下：
	1、先执行when='setup'，返回setup 的执行结果
	2、然后执行when='call'，返回call 的执行结果
	3、最后执行when='teardown'，返回teardown 的执行结果

	运行用例的过程会经历三个阶段:setup-call-teardown,
	每个阶段都会返回的 Result 对象和 TestReport 对象，以及对象属性。
	:param item: 测试用例
	:param call: 用例步骤
	:return:
	"""
	outcome = yield  # 获取钩子方法的调用结果
	report = outcome.get_result()  # 从调用结果中获取测试报告

	# 只获取用例运行时失败的结果，即when='call'
	if report.when == 'call' and report.failed:
		now_time = time.strftime('%Y_%m_%d_%H_%M_%S')
		# 用例失败，添加allure报告截图
		if hasattr(m_page.driver, 'get_screenshot_as_png'):
			with allure.step('添加失败截图'):
				logger.info(f'添加失败截图')
				allure.attach(m_page.driver.get_screenshot_as_png(), f'失败截图_{now_time}',
				              allure.attachment_type.PNG)


def pytest_collection_modifyitems(
		session: "Session", config: "Config", items: List["Item"]
) -> None:
	"""
	修改测试用例名称编码，执行顺序
	:param session: pytest session 对象
	:param config: 配置信息对象
	:param items: 收集到的所有测试用例对象列表，name：用例名称，nodeid：用例路径
	:return:
	"""
	for item in items:
		# 修改用例名称和路径的编码
		# nodeid是用例对象的属性方法，真正改变的是用例对象的_nodeid属性
		item.name = item.name.encode('utf-8').decode('unicode-escape')
		item._nodeid = item.nodeid.encode('utf-8').decode('unicode-escape')


@pytest.fixture(scope="session", autouse=True)
def manage_logs(request):
	"""设置日志文件的文件名称"""
	now = time.strftime("%Y-%m-%d %H-%M-%S")
	log_name = 'log/' + now + '.log'

	request.config.pluginmanager.get_plugin("logging-plugin").set_log_path(log_name)
